package main

import (
	"bytes"
	"context"
	"crypto/md5"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
	"sync"
	"time"
)

func doConn() {
	client, err := clientv3.New(clientv3.Config{Endpoints: []string{"127.0.0.1:2379"},
		DialTimeout: 3 * time.Second})
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("connect success")
	defer client.Close()
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	_, err = client.Put(ctx, "key", "value")
	cancel()
	if err != nil {
		fmt.Printf("put to etcd failed, err:%v\n", err)
		return
	}
	// get
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	resp, err := client.Get(ctx, "lmh")
	cancel()
	if err != nil {
		fmt.Printf("get from etcd failed, err:%v\n", err)
		return
	}
	for k, v := range resp.Kvs {
		fmt.Println(k, v)
	}
}

func doServe() {
	var srv http.Server
	var wg sync.WaitGroup
	register := func(f func()) {
		wg.Add(1)
		log.Println("Exit func register")
		srv.RegisterOnShutdown(func() {
			defer wg.Done()
			f()
			log.Println("Exit func done")
		})
	}
	register(func() {
		time.Sleep(3 * time.Second)
		log.Println("Called on Shutdown")
	})
	idleConnsClosed := make(chan struct{})
	go func() {
		sigint := make(chan os.Signal, 1)
		signal.Notify(sigint, os.Interrupt)
		<-sigint
		// We received an interrupt signal, shut down.
		log.Println("Shutdown start")
		if err := srv.Shutdown(context.Background()); err != nil {
			// Error from closing listeners, or context timeout:
			log.Printf("HTTP server Shutdown: %v", err)
		}
		close(idleConnsClosed)
	}()

	if err := http.ListenAndServe(":8080", nil); err != http.ErrServerClosed {
		// Error starting or closing listener:
		log.Fatalf("HTTP server ListenAndServe: %v", err)
	}
	<-idleConnsClosed
	log.Println("Shutdown finish")
	wg.Wait()
}

func go1() {
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		//panic("协程发生错误")

	}()
	wg.Wait()
	fmt.Println("主程序结束")
}

func go2() {
	ch := make(chan int)
	go func(out chan<- int) {
		for i := 0; ; i++ {
			select {
			case out <- i:
				fmt.Printf("producer: produce %d\n", i)
				time.Sleep(time.Second)
			}
		}
	}(ch)
	go func(in <-chan int) {
		for true {
			select {
			case i := <-in:
				fmt.Printf("comsumer:consumed %d\n", i)
			}
		}
	}(ch)
	time.Sleep(100000000 * time.Second)
}

func go3() {
	ctx, cancelFunc := context.WithCancel(context.Background())
	go func(ctx context.Context) {
		defer fmt.Println("worker stopped")
		for true {
			select {
			case <-ctx.Done():
				return
			default:
				fmt.Println("working")
			}
			time.Sleep(time.Second)
		}
	}(ctx)
	time.Sleep(4 * time.Second)
	cancelFunc()
	time.Sleep(2 * time.Second)
}

type Singleton struct {
}

var (
	instance *Singleton
	once     sync.Once
)

func GetInstance() *Singleton {
	once.Do(func() {
		instance = &Singleton{}
	})
	return instance
}

func doOnce() {
	var wg sync.WaitGroup
	for i := 0; i < 5; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			instance := GetInstance()
			fmt.Printf("instance addr:%p\n", instance)
		}()
	}
	wg.Wait()
}

type Config struct {
	config map[string]string
}

var config *Config

func getConf() *Config {
	once.Do(func() {
		fmt.Println("init config...")
		config = &Config{
			config: map[string]string{
				"c1": "v1",
				"c2": "v2",
			},
		}
	})
	return config
}

type BytesBufferPool struct {
	mu   sync.Mutex
	pool []*bytes.Buffer
}

func (p *BytesBufferPool) Get() *bytes.Buffer {
	p.mu.Lock()
	defer p.mu.Unlock()
	n := len(p.pool)
	if n == 0 {
		return &bytes.Buffer{}
	}
	v := p.pool[n-1]
	p.pool[n-1] = nil
	p.pool = p.pool[:n-1]
	return v
}

func (p *BytesBufferPool) Put(buf *bytes.Buffer) {
	if buf == nil {
		return
	}
	p.mu.Lock()
	defer p.mu.Unlock()
	p.pool = append(p.pool, buf)
}

var buffers BytesBufferPool

var bufPool sync.Pool = sync.Pool{
	New: func() interface{} {
		return &bytes.Buffer{}
	},
}

func toJson(m map[string]int) (string, error) {
	//buf := buffers.Get()
	//defer buffers.Put(buf)
	buf := bufPool.Get().(*bytes.Buffer)
	bufPool.Put(buf)
	buf.WriteString("{")
	for k, v := range m {
		buf.WriteString(fmt.Sprintf(`"%s":%d`, k, v))
	}
	if len(m) > 0 {
		buf.Truncate(buf.Len() - 1)
	}
	buf.WriteString("}")
	return buf.String(), nil
}

var tcpPool = &sync.Pool{
	New: func() interface{} {
		conn, err := net.Dial("tcp", "localhost:8080")
		if err != nil {
			panic(err)
		}
		return conn
	},
}

func doConn2() {
	for i := 0; i < 100; i++ {
		conn := tcpPool.Get().(net.Conn)
		time.Sleep(100 * time.Millisecond)
		fmt.Fprintf(conn, "GET / HTTP/1.0 \r\n\r\n")
		tcpPool.Put(conn)
	}
}

func test1() {
	i, j := 0, 0
	k := 1
	fmt.Println(i, j, k)
}

func Greeting(prefix string, who ...string) {
	if who == nil {
		fmt.Println("nobody to say hi")
		return
	}
	for _, ele := range who {
		fmt.Printf("%s %s\n", prefix, ele)
	}
}
func ExampleGreetingWithSlice() {
	guest := []string{"Joe", "Anna", "Eileen"}
	Greeting("hello:", guest...)
}

func doStr() {
	str := "abc"
	for i, ele := range str {
		fmt.Printf("%d=>%s\n", i, string(ele))
	}
}

func doHash() {
	data := []byte("hello")
	buf := make([]byte, 4096)
	hash := md5.New()
	copy(buf, data)
	hash.Write(buf)
	sum := hash.Sum(nil)
	fmt.Printf("%x", sum)
}
func doHashChunk() {
	data := []byte("hello")
	var wg sync.WaitGroup
	chunkSize := 4
	hash := md5.New()
	for i := 0; i < chunkSize; i++ {
		wg.Add(1)
		go func(chunkIdx int) {
			defer wg.Done()
			start := chunkIdx * len(data) / chunkSize
			end := (chunkIdx + 1) * len(data) / chunkSize
			hash.Write(data[start:end])
		}(i)
		wg.Wait()
		ret := hash.Sum(nil)
		fmt.Printf("%x\n", ret)
	}
}
func main() {
	doHash()
}
